﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using devtm.Aop.Behavior;
using System.Text.RegularExpressions;

namespace devtm.Aop.InternalProcess.Lock
{

    public class LockStrategy : ILockStrategy
    {       


        public virtual bool GetKey(Event.InterceptEventArgs args, out uint key)
        {

            key = 0;

            if (ResolveStrategyFor(args))
            {
                key = GetUniqueKey(args);
                return true;
            }

            return false;

        }
 


        #region Compute Key
        
        protected virtual uint GetUniqueKey(Event.InterceptEventArgs args)
        {

            string k;

            if (args.Properties.Contains("Key"))
            {
                k = ComputeMaskKey((string)args.Properties.Get("Key"), args);
            }
            else
            {
                string fullMethodName = args.Member.DeclaringType.FullName + args.Member.Name;
                k = ComputeParameters(fullMethodName, args);
            }

            uint retour = Crc32.Calculate(k);

            return retour;
        }


        private string ComputeMaskKey(string mask, Event.InterceptEventArgs args)
        {            
            string retour = mask;
            var parameters = args.Parameters;
            foreach (Match item in search.Matches(mask))
            {

                string vv = item.Value.Substring(1, item.Value.Length - 2);

                switch (item.Value)
                {

                    case "name":
                        retour.Replace(vv, args.Member.Name);
                        break;

                    case "threadid":
                        retour.Replace(vv, System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
                        break;

                    default:
                        if (parameters.ContainsKey(vv))
                        {
                            retour.Replace(vv, GetParameterValue(parameters[vv]));
                            continue;
                        }
                        break;

                }
            }

            return retour;
        }


        private static string ComputeParameters(string fullMethodName, Event.InterceptEventArgs args)
        {

            StringBuilder s = new StringBuilder(fullMethodName);
            foreach (var item in args.parameters)
                s.Append(GetParameterValue(item));

            return s.ToString();

        }


        private static string GetParameterValue(object item)
        {
            string ret;

            if (item is string)
                ret = item as string;
            else
            {
                Type t = item.GetType();

                if (t.IsClass)
                    ret = item.GetHashCode().ToString();

                else if (t.IsEnum)
                    ret = ((int)item).ToString();

                else
                    ret = item.ToString();

            }

            return ret;

        }
        #endregion


        public virtual bool ResolveStrategyFor(Event.InterceptEventArgs args)
        {

            if (args.Properties.Contains("Behevior"))
            {
                
                BehaviorEnum t = (BehaviorEnum)args.Properties.Get("Behevior");
                
                if (t == BehaviorEnum.Ignore)
                    return false;

            }

            return true;

        }

        private Regex search = new Regex(@"\{[\w\d]*\}");

    }
}
